using FI.BatchJob.Web.Data;
using FI.BatchJob.Web.Extensions;
using FI.BatchJob.Web.QuartzNet;
using FI.BatchJob.Web.Services;
using FI.BatchJob.Web.SignalR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Serialization;
using Quartz.Impl.AdoJobStore;
using Quartz.Impl.AdoJobStore.Common;
using Serilog;
using System;

namespace FI.BatchJob.Web

{
    /// <summary>
    /// 
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Startup"/> class.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;

        }

        /// <summary>
        /// Gets the configuration.
        /// </summary>
        /// <value>
        /// The configuration.
        /// </value>
        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddDbContext<ApplicationDbContext>(options =>
              options.UseSqlite(Configuration.GetConnectionString("SqliteConnection")));


            services.AddIdentity<IdentityUser, IdentityRole>(options =>
            {
                // Password settings
                options.Password.RequireDigit = false;
                options.Password.RequiredLength = 6;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
                options.Password.RequireLowercase = false;
                options.Password.RequiredUniqueChars = 1;

                // Lockout settings
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
                options.Lockout.MaxFailedAccessAttempts = 10;
                options.Lockout.AllowedForNewUsers = true;

                // User settings
                //options.User.RequireUniqueEmail = true;

                // email confirmation require
                //options.SignIn.RequireConfirmedEmail = true;
            })
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddErrorDescriber<CustomIdentityErrorDescriber>().AddDefaultTokenProviders(); ;


            // cookie settings
            //services.ConfigureApplicationCookie(options =>
            //{
            //    // Cookie settings
            //    options.Cookie.HttpOnly = true;
            //    options.ExpireTimeSpan = TimeSpan.FromDays(60);
            //    options.LoginPath = "/Account/Login"; // If the LoginPath is not set here, ASP.NET Core will default to /Account/Login
            //    options.LogoutPath = "/Account/Logout"; // If the LogoutPath is not set here, ASP.NET Core will default to /Account/Logout
            //    options.AccessDeniedPath = "/Account/AccessDenied"; // If the AccessDeniedPath is not set here, ASP.NET Core will default to /Account/AccessDenied
            //    options.SlidingExpiration = true;
            //});


            services.AddControllersWithViews().AddRazorRuntimeCompilation().AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();

            });


            services.AddCors();

            services.AddSignalR();

            services.AddTransient<IEmailSender, EmailSender>();

            services.AddHostedService<HostClearHistoryService>();

            services.AddHostedService<HostSendEmailService>();

            services.AddSingleton(BuildScheduler());

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHubContext<TaskUpdateHub> hubContext)
        {
            ServiceLocator.Instance = app.ApplicationServices;

            if (env.EnvironmentName == "Development")
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseDeveloperExceptionPage();
            app.UseStaticFiles();

            app.UseHttpsRedirection();



            app.UseCors();

            app.UseRouting();

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();

                endpoints.MapHub<TaskUpdateHub>("/RefreshTask");
            });

            PubSub.Hub.Default.Subscribe<string>(this, async h =>
            {
                try
                {
                    await hubContext.Clients.All.SendAsync("ReceiveMessage", "", "RefreshTask");

                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Hub subscriber failed to send");

                }
            });

        }

        /// <summary>
        /// Builds the scheduler.
        /// </summary>
        /// <returns></returns>
        private SchedulerCenter BuildScheduler()
        {
            string dbProviderName = "SQLite-Microsoft";// "SQLite"

            string connectionString = Configuration.GetConnectionString("SqliteConnection");

            string driverDelegateType = typeof(SQLiteDelegate).AssemblyQualifiedName;

            SchedulerCenter schedulerCenter = SchedulerCenter.Instance;

            schedulerCenter.Setting(new DbProvider(dbProviderName, connectionString), driverDelegateType);

            schedulerCenter.StartScheduleAsync().Wait();

            return schedulerCenter;
        }

    }
}
